{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "C++数组在内存中的分配\n",
    "接前一篇的内容，C++中数组在内存中也有静态分配和动态分配的区别。静态数组建立的方式为：A a[]，它在栈上分配空间;动态方式是使用new，malloc在堆上分配。\n",
    "\n",
    "数组要么在静态存储区被创建（如全局数组），要么在栈或堆上被创建。数组名对应着（而不是指向）一块内存，其地址与容量在生命期内保持不变，只有数组的内容可以改变。看下例：\n",
    "\n",
    "复制代码\n",
    " 1 #include<iostream>\n",
    " 2 using namespace std;\n",
    " 3  void test()\n",
    " 4  {\n",
    " 5      char ch[]=\"hello\";\n",
    " 6      ch[0]='H';\n",
    " 7      char*p=\"world\";\n",
    " 8      p[0]='W';//出错\n",
    " 9      cout<<ch<<endl;\n",
    "10      cout<<p<<endl;\n",
    "11  }\n",
    "12 int main()\n",
    "13 {\n",
    "14     test();\n",
    "15     return 0;\n",
    "16 }\n",
    "复制代码\n",
    "程序中用指针指向了一个常量字符串\"world\",C++常量字符串存在常量存储区，且不能修改，故会出错。\n",
    "数组的在栈上分配，或堆上分配的区别可以看下例：将test和main函数修改为下\n",
    "\n",
    "复制代码\n",
    " 1 char* test()\n",
    " 2 {\n",
    " 3     char ch[]=\"hello\";//在栈上\n",
    " 4 /*    char* ch= new char[6];//在堆上\n",
    " 5     ch[0]='h';\n",
    " 6     ch[1]='e';\n",
    " 7     ch[2]='l';\n",
    " 8     ch[3]='l';\n",
    " 9     ch[4]='0';\n",
    "10     ch[5]='\\0';\n",
    "11     */\n",
    "12     return ch;\n",
    "13 }\n",
    "14 int main()\n",
    "15 {\n",
    "16 char*p=test();\n",
    "17 cout<<p<<endl;\n",
    "18 return 0;\n",
    "19 }\n",
    "复制代码\n",
    "很明显程序程序编译时出现：warning C4172: returning address of local variable or temporary。在test调用结束后在栈上分配的数组已经销毁，p即为野指针指向无效内容。这里把数组名作为l函数返回值。如果换成下面注释的代码在堆上分配则没有问题，注意最后的'\\0'，字符串的最后是以'\\0'来判断结束的，不然会出界输出无效内容。这里可以看出C++数组在内存中的存储形式与上篇内容介绍的一样。将test改为如下：\n",
    "\n",
    "复制代码\n",
    " 1 char* test()\n",
    " 2 {\n",
    " 3     char* ch= new char[6];//在堆上\n",
    " 4     ch[0]='h';\n",
    " 5     ch[1]='e';\n",
    " 6     ch[2]='l';\n",
    " 7     ch[3]='l';\n",
    " 8     ch[4]='0';\n",
    " 9     ch[5]='\\0';    \n",
    "10 char c[] = \"hello world\";\n",
    "11 char *p = c;\n",
    "12 cout<< sizeof(c) << endl; // 12字节\n",
    "13 cout<< sizeof(ch) << endl; // 4字节\n",
    "14 cout<< sizeof(p) << endl; // 4字节\n",
    "15     return ch;\n",
    "16 }\n",
    "复制代码\n",
    "静态数组名用sizeof可以知道数组实际所占的内存大小，而指向数组的指针占用空间即为普通指针的大小。当数组作为函数的参数进行传递时，该数组自动退化为同类型的指针。\n",
    "\n",
    "在上一篇关于C++中类在内存中分配的介绍举例时发现一个问题，当两个指针指向同一个对象时，发现delete一个指针销毁该对象后，用另一个指针扔能调用该类的函数，这个是野指针应该有错啊。看下面的例子：\n",
    "\n",
    "复制代码\n",
    " 1 #include<iostream>\n",
    " 2 using namespace std;\n",
    " 3  class A\n",
    " 4  {\n",
    " 5  public:\n",
    " 6      void fun()\n",
    " 7      {\n",
    " 8          cout<<\"class of a:\"<<endl;\n",
    " 9      }\n",
    "10      int num;\n",
    "11  };\n",
    "12   A* test()\n",
    "13  {\n",
    "14     A*p;\n",
    "15     A a;\n",
    "16     a.num=11;\n",
    "17     p=&a;\n",
    "18 p->fun();\n",
    "19 return p;\n",
    "20  }\n",
    "21 int main()\n",
    "22 {\n",
    "23 A*s=test();\n",
    "24 s->fun();\n",
    "25 return 0;\n",
    "26 }\n",
    "复制代码\n",
    "程序运行结果：\n",
    "\n",
    "\n",
    "即两次输出class of a，一次是在test函数内，一次是s调用。test内的a分配在栈上，函数结束后应该就销毁了，为什么s还能调用fun。原来类中的成员数据和函数是存放在不同位置的。C++类的方法存放在\"程序代码区\"，而类中的数据成员（对象数据成员）存放在类的实例对象中，即该成员数据存放在堆或栈中。s指向对象的成员数据已销毁，而类的方法还在。\n",
    "\n",
    "若将上面代码第8行改为：cout<<\"class of a:\"<<this->num<<endl;程序运行结果为：\n",
    "\n",
    " \n",
    "\n",
    " 即s输出的数据成员num为无效，因为该对象已释放。关于C++内存管理还有很多内容，需要进一步加强学习。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
